/**************************************************************************** 
 * Meta，一个轻量级的静态分区Hypervisor 
 *
 * 版权(c) , 2022-
 *
 * 作者:
 *      Tupelo Shen <shenwanjiang2013@163.com>
 *
 * Meta是一个自由软件，你可以在遵循GNU GPLv2协议的条件下，重新修改并发布它。
 *
 ***************************************************************************/

#ifndef __MEM_H__
#define __MEM_H__

#include <meta.h>
#include <arch/mem.h>
#include <page_table.h>
#include <list.h>
#include <spinlock.h>
#include <cache.h>

// #ifndef __ASSEMBLER__

/* 地址空间类型 */
enum AS_TYPE { AS_HYP = 0, AS_VM, AS_HYP_CPY };
/* 地址空间中内存段类型 */
enum AS_SEC {
    /*--- HYP AS SECTIONS -----*/
    SEC_HYP_GLOBAL = 0,
    SEC_HYP_IMAGE,
    SEC_HYP_DEVICE,
    SEC_HYP_PRIVATE,
    SEC_HYP_VM,
    SEC_HYP_ANY, /* must be last */
    /*--- VM AS SECTIONS -----*/
    SEC_VM_ANY = 0, /* must be last */
};

#define HYP_ASID  0

/* 地址空间定义的数据结构 */
struct addr_space {
    struct page_table   pt;     /* 页表 */
    enum AS_TYPE        type;   /* 地址空间类型：AS_HYP，AS_VM，AS_HYP_CPY */
    colormap_t          colors; /* 内存染色 */
    asid_t              id;     /* 地址空间的ID */
    spinlock_t          lock;   /* 保护该数据结构的锁 */
};

struct ppages {
    paddr_t     base;
    size_t      size;
    colormap_t  colors;
};

struct mem_region {
    paddr_t     base;
    size_t      size;
    colormap_t  colors;
    bool        place_phys;
    paddr_t     phys;
};

struct dev_region {
    paddr_t     pa;
    vaddr_t     va;
    size_t      size;
    size_t      interrupt_num;
    irqid_t     *interrupts;
    streamid_t  id; /* bus master id for iommu effects */
};

struct shmem {
    size_t      size;
    colormap_t  colors;
    bool        place_phys;
    paddr_t     phys;
    cpumap_t    cpu_masters;
};

/****************************************************************************
 ************************** 私有函数接口 ************************************
 ****************************************************************************/
static inline struct ppages mem_ppages_get(paddr_t base, size_t size)
{
    return (struct ppages){.colors = 0, .base = base, .size = size};
}

static inline bool all_clrs(colormap_t clrs)
{
    return (clrs == 0) ||
           ((clrs & ((1ULL << COLOR_NUM) - 1)) == ((1ULL << COLOR_NUM) - 1));
}

/****************************************************************************
 ************************** 公共函数接口 ************************************
 ****************************************************************************/
void            mem_init(paddr_t load_addr, paddr_t config_addr);
void            as_init(struct addr_space*  as,
                        enum AS_TYPE        type,
                        asid_t              id,
                        pte_t*              root_pt,
                        colormap_t          colors);
void*           mem_alloc_page(size_t n, enum AS_SEC sec, bool phys_aligned);
struct ppages   mem_alloc_ppages(colormap_t colors, size_t n, bool aligned);
vaddr_t         mem_alloc_vpage(struct addr_space*  as,
                                enum AS_SEC         section,
                                vaddr_t             at,
                                size_t              n
                                );
void            mem_free_vpage(struct addr_space*   as,
                                vaddr_t             at,
                                size_t              n,
                                bool                free_ppages
                                );
bool            mem_map(struct addr_space*          as,
                                vaddr_t             va,
                                struct ppages*      ppages,
                                size_t              n,
                                pte_t               flags
                                );
bool            mem_map_reclr(struct addr_space*    as,
                                vaddr_t             va,
                                struct ppages*      ppages,
                                size_t              n,
                                pte_t               flags
                                );
bool            mem_map_dev(struct addr_space*      as,
                                vaddr_t             va,
                                paddr_t             base,
                                size_t              n
                                );

/* 这两个函数与架构相关，所以实现代码位于arch目录下的文件中 */
void            as_arch_init(struct addr_space* as);
bool            mem_translate(struct addr_space* as, vaddr_t va, paddr_t* pa);

// #endif /* |__ASSEMBLER__ */

#endif /* __MEM_H__ */
